package com.atguigu.system.filter;

import com.atguigu.common.result.Result;
import com.atguigu.common.result.ResultCodeEnum;
import com.atguigu.common.util.ResponseUtil;
import com.atguigu.model.vo.LoginVo;
import com.atguigu.system.custom.CustomUser;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 登录认证过滤器
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {


    RedisTemplate redisTemplate;

    public TokenLoginFilter(AuthenticationManager authenticationManager,RedisTemplate redisTemplate){
        super.setAuthenticationManager(authenticationManager);
        this.redisTemplate = redisTemplate;
        //只拦截登录请求路径，别的路径不拦截。
        this.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/admin/system/index/login","POST"));
    }


    /*
    没有直接重写doFilter()方法，而是重写attemptAuthentication()方法。预留的方法。
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        super.doFilter(req, res, chain);
    }*/

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        /*if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }*/

        try {
            LoginVo loginVo = (LoginVo) new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);

            String username = loginVo.getUsername().trim();
            String password = loginVo.getPassword();

            //Object principal 用户名称, Object credentials 用户密码
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username,password);

            return this.getAuthenticationManager().authenticate(authentication);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain,
            //验证用户名称和密码等信息的 认证对象
            Authentication authResult) throws IOException, ServletException {

        CustomUser customUser = (CustomUser)authResult.getPrincipal();

        String token = UUID.randomUUID().toString().replaceAll("-", "");
        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        redisTemplate.boundValueOps(token).set(customUser.getSysUser(),2, TimeUnit.HOURS);

        ResponseUtil.out(response, Result.ok(map));
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        ResponseUtil.out(response, Result.build(null, 444,failed.getMessage()));
    }
}
